﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Windows.Controls;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Windows.UI.Modules.Couple.BusinessEntities;
using StockholmsStad.Windows.UI.Modules.Couple.Interfaces;
using StockholmsStad.Windows.UI.Modules.Couple.Models;

namespace StockholmsStad.Windows.UI.Modules.Couple.Controls
{
    /// <summary>
    /// Interaction logic for OrdinaryBookingControl.xaml
    /// </summary>
    public partial class OrdinaryBookingControl : IOrdinaryBookingView
    {
        private readonly IBookingService bookingService;
        private readonly ICoupleService coupleService;
        private List<BookingTimeBlock> allTimeBlocks;
        private ObservableCollection<DateTime> times;
        private ObservableCollection<DateTime> days;
        private BookingPresentationModel model;

        public OrdinaryBookingControl(IBookingService bService, ICoupleService cService)
        {
            bookingService = bService;
            coupleService = cService;
            Initialized += OrdinaryBookingControl_Initialized;
            InitializeComponent();

            Loaded += OrdinaryBookingControl_Loaded;
            DataContextChanged += OrdinaryBookingControl_DataContextChanged;
            calendarControl.SelectedDatesChanged += calendarControl_SelectedDatesChanged;
        }

        #region IOrdinaryBookingView Members

        public BookingPresentationModel Model
        {
            get { return DataContext as BookingPresentationModel; }
            set { DataContext = value; }
        }

        #endregion

        private void OrdinaryBookingControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (IsLoaded)
            {
                var nonAvailableDates = coupleService.GetNonAvailableDates();
                foreach (var date in nonAvailableDates)
                {
                    BlackoutDates(calendarControl, date);
                }

                var nonFullyDates = coupleService.GetNonFullyBookedDates();
                var popUpCalendar1 = PreferredDate1Picker.PopUpCalendar;
                var popUpCalendar2 = PreferredDate2Picker.PopUpCalendar;
                foreach (var date in nonFullyDates)
                {
                    BlackoutDates(popUpCalendar1, date);
                    BlackoutDates(popUpCalendar2, date);
                }
                Model.IsInChangeMode = false;
            }
        }

        private static void BlackoutDates(Calendar calendar, DateRange dateRange)
        {
            var bDate = calendar.SelectedDate;

            //Måste ta bort tiden för att få rättvis jämförelse
            var sd = bDate != null ? bDate.Value.Date.CompareTo(dateRange.StartDate) : 1;
            var ed = bDate != null ? bDate.Value.Date.CompareTo(dateRange.EndDate) : 1;
            if ((sd > 0 && ed > 0) || (sd < 0 && ed < 0))
            {
                calendar.BlackoutDates.Add(new CalendarDateRange { Start = dateRange.StartDate, End = dateRange.EndDate });
            }
            else
            {
                //Om man har valt dag som är fullbokad måste vi göra den dagen till valbar
                //annars får man ArgumentOutOfRangeException
                var newEndDate = bDate.Value.Date.Subtract(new TimeSpan(1, 0, 0, 0));
                var newStartDate = bDate.Value.Date.AddDays(1);
                if (newEndDate.CompareTo(dateRange.StartDate) > 0)
                {
                    calendar.BlackoutDates.Add(new CalendarDateRange {Start = dateRange.StartDate, End = newEndDate});
                }
                if (newStartDate.CompareTo(dateRange.EndDate) < 0)
                {
                    calendar.BlackoutDates.Add(new CalendarDateRange { Start = newStartDate, End = dateRange.EndDate });
                }
            }
        }

        private void OrdinaryBookingControl_Initialized(object sender, EventArgs e)
        {
            allTimeBlocks = bookingService.GetFreeTimeBlocks().BookingTimeBlocks;

            if (allTimeBlocks != null)
            {
                int range = allTimeBlocks.Count > 10 ? 10 : allTimeBlocks.Count;
                listViewNearestTime.ItemsSource = allTimeBlocks.GetRange(0, range);
            }
        }

        private void OrdinaryBookingControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            model = DataContext as BookingPresentationModel;

            if (model == null)
                return;

            // Kolla om det finns en bokning
            if (model.BookedDate != null)
            {
                var items = new ObservableCollection<DateTime> {model.BookedDate.StartDateTime};
 
                ComboBoxTime.ItemsSource = items;
                ComboBoxDay.ItemsSource = items;

                ComboBoxDay.SelectedIndex = FindDayIndex(model.BookedDate.StartDateTime);
                ComboBoxTime.SelectedIndex = FindTimeIndex(model.BookedDate.StartDateTime.TimeOfDay);

                TextBoxMonth.Text = model.BookedDate.StartDateTime.ToString("yyyy-MM");
                calendarControl.DisplayDate = model.BookedDate.StartDateTime;
                calendarControl.SelectedDate = model.BookedDate.StartDateTime;

                SetBlackoutDates(model.BookedDate.StartDateTime);

                //calendarControl.BlackoutDates.AddDatesInPast();

                CheckBoxBookOrdinaryDateTime.IsChecked = true;
            }
            else
            {
                ComboBoxTime.ItemsSource = null;
                ComboBoxDay.ItemsSource = null;
                TextBoxMonth.Text = string.Empty;
                CheckBoxBookOrdinaryDateTime.IsChecked = false;
            }

            if (model.PreferredDate1.HasValue)
            {
                CheckBoxBookPreferredDate1.IsChecked = true;
                CheckBoxBookPreferredDate2.IsEnabled = true;
            }
            else
            {
                CheckBoxBookPreferredDate1.IsChecked = false;
                CheckBoxBookPreferredDate2.IsEnabled = false;
                
            }
            if (model.PreferredDate2.HasValue)
            {
                CheckBoxBookPreferredDate2.IsChecked = true;
            }
            else
            {
                CheckBoxBookPreferredDate2.IsChecked = false;
            }
            CancelButton.IsEnabled = true;
        }

        // Återigen en bugg i datumkontrollen. Om bokningsdatum ligger bakåt i tiden,
        // kan inte den "blackas ut" får då kan inte selected date sättas (vilket vi
        // vill kunna göra). Denna kod återfinns i individualbookingcontrol.xaml.cs, så
        // ändringar i denna kräver ändringar även i ordinarybooking
        private void SetBlackoutDates(DateTime bookedDate)
        {
            // rensa tidigare blackout-dagar
            calendarControl.BlackoutDates.Clear();
            if (bookedDate.CompareTo(DateTime.Now) <= 0)
            {
                calendarControl.BlackoutDates.Add(new CalendarDateRange
                                                      {
                                                          Start = DateTime.MinValue,
                                                          End = bookedDate.Date.AddDays(-1)
                                                      });
                calendarControl.BlackoutDates.Add(new CalendarDateRange
                                                      {
                                                          Start = bookedDate.Date.AddDays(1),
                                                          End = DateTime.Now.AddDays(1)
                                                      });
            }
            else
            {
                calendarControl.BlackoutDates.AddDatesInPast();
            }
        }

        private void GetDaysForMonth(int month)
        {
            if(model != null)
            {
                var timesBlocksForMonth = allTimeBlocks.Where(t => t.TimeBlock.StartDateTime.Month == month).ToList();
                var availableDays = timesBlocksForMonth.Where(t => t.TimeBlock.StartDateTime.Month == month).
                    Select(t => t.TimeBlock.StartDateTime.Date).Distinct().ToList();
                days = new ObservableCollection<DateTime>(availableDays);
                ComboBoxDay.ItemsSource = days;
            }
        }

        private void GetTimesForDay(DateTime date)
        {
            if (model != null)
            {
                var availableTimes =
                    allTimeBlocks.Where(
                        t => t.TimeBlock.StartDateTime.Month == date.Month && t.TimeBlock.StartDateTime.Day == date.Day).
                        Select(t => t.TimeBlock.StartDateTime).ToList();
                times = new ObservableCollection<DateTime>(availableTimes);
                ComboBoxTime.ItemsSource = times;
            }
        }

        private void CheckBoxBookOrdinaryDateTime_Checked(object sender, RoutedEventArgs e)
        {
            if(string.IsNullOrEmpty(TextBoxMonth.Text))
            {
                MessageBox.Show("Du måste ange ett datum. Välj i kalendern/listan till höger. ", 
                    "Information", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                CheckBoxBookOrdinaryDateTime.IsChecked = false;
                return;
            }

            if(ComboBoxDay.SelectedItem == null)
            {
                MessageBox.Show("Du måste ange en dag. Välj i listan för dagar. ",
                    "Information", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                CheckBoxBookOrdinaryDateTime.IsChecked = false;
                return;
            }

            if (ComboBoxTime.SelectedItem == null)
            {
                MessageBox.Show("Du måste ange en tid. Välj i listan för tider. ",
                    "Information", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                CheckBoxBookOrdinaryDateTime.IsChecked = false;
                return;
            }

            if(model != null)
            {
                BindControlsToBookingDate();
            }
        }

        //Flyttar över informationen i textbox och dropdowns till BookingDate
        private void BindControlsToBookingDate()
        {
            if (!string.IsNullOrEmpty(TextBoxMonth.Text) &&
                ComboBoxDay.SelectedItem != null && ComboBoxTime.SelectedItem != null)
            {
                var date = (DateTime)ComboBoxDay.SelectedValue;
                var time = (DateTime)ComboBoxTime.SelectedItem;
                var selected = new DateTime(date.Year, date.Month, date.Day, time.Hour, time.Minute, 0);
                var id = allTimeBlocks.Where(t => t.TimeBlock.StartDateTime.CompareTo(selected) == 0).
                    Select(t => t.TimeBlock.TimeBlockId).FirstOrDefault();

                model.BookedDate = new TimeBlock { StartDateTime = selected, TimeBlockId = id };

                SaveButton.IsEnabled = true;
            }
        }

        private void CheckBoxBookPreferredDate1_Checked(object sender, RoutedEventArgs e)
        {
            if(model == null)
                return;

            if (!model.PreferredDate1.HasValue)
            {
                MessageBox.Show("Du måste ange ett datum. Välj i kalender till vänster. ",
                    "Information", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                CheckBoxBookPreferredDate1.IsChecked = false;
                return;
            }

            CheckBoxBookPreferredDate2.IsEnabled = true;
            SaveButton.IsEnabled = true;
        }

        private void CheckBoxBookPreferredDate2_Checked(object sender, RoutedEventArgs e)
        {
            if (model == null)
                return;

            if (!model.PreferredDate2.HasValue)
            {
                MessageBox.Show("Du måste ange ett datum. Välj i kalender till vänster. ",
                    "Information", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                CheckBoxBookPreferredDate2.IsChecked = false;
                return;
            }

            SaveButton.IsEnabled = true;
        }

        private void listViewNearestTime_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (IsLoaded && e.AddedItems != null && e.AddedItems.Count > 0 && model != null)
            {
                var bookingTimeBlock = e.AddedItems[0] as BookingTimeBlock;
                if (bookingTimeBlock != null)
                {
                    TextBoxMonth.Text = bookingTimeBlock.TimeBlock.StartDateTime.ToString("yyyy-MM");
                    var selectedDate = bookingTimeBlock.TimeBlock;

                    // Clear previous items from list
                    ComboBoxDay.ItemsSource = null;
                    ComboBoxTime.ItemsSource = null;

                    // Add selected item to the list
                    var items = new ObservableCollection<DateTime> { selectedDate.StartDateTime };
                    ComboBoxDay.ItemsSource = items;
                    ComboBoxTime.ItemsSource = items;

                    ComboBoxDay.SelectedIndex = FindDayIndex(selectedDate.StartDateTime);
                    ComboBoxTime.SelectedIndex = FindTimeIndex(selectedDate.StartDateTime.TimeOfDay);

                    SaveButton.IsEnabled = true;
                }
            }
            else
            {
                listViewNearestTime.SelectedItem = null;
            }
        }

        private void calendarControl_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
        {
            if (IsLoaded && e.AddedItems != null && e.AddedItems.Count > 0)
            {
                // Clear previous items from list
                ComboBoxDay.ItemsSource = null;
                ComboBoxTime.ItemsSource = null;

                var date = Convert.ToDateTime(e.AddedItems[0]);
                TextBoxMonth.Text = date.ToString("yyyy-MM");
                GetDaysForMonth(date.Month);
                ComboBoxDay.SelectedIndex = FindDayIndex(date);

                SaveButton.IsEnabled = false;
            }
        }

        private void ComboBoxDay_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (IsLoaded && e.AddedItems != null && e.AddedItems.Count > 0 && !IsNearestItemLoaded())
            {
                var date = Convert.ToDateTime(e.AddedItems[0]);
                GetTimesForDay(date);
            }
        }

        private bool IsNearestItemLoaded()
        {
            if(TabControlTimes.SelectedItem != null)
            {
                var tabItem = TabControlTimes.SelectedItem as TabItem;
                if(tabItem != null && tabItem.Name == TabItemNearestTimes.Name)
                    return true;
            }

            return false;
        }

        private int FindDayIndex(DateTime date)
        {
            for(int i = 0; i < ComboBoxDay.Items.Count; i++)
            {
                var item = (DateTime)ComboBoxDay.Items[i];
                if(item.CompareTo(date) == 0)
                    return i;
            }

            return -1;
        }

        private int FindTimeIndex(TimeSpan time)
        {
            for (int i = 0; i < ComboBoxTime.Items.Count; i++)
            {
                var item = (DateTime)ComboBoxTime.Items[i];
                if (item.TimeOfDay.Hours == time.Hours && item.TimeOfDay.Minutes == time.Minutes)
                    return i;
            }

            return -1;
        }

        private void ClearControls()
        {
            TextBoxMonth.Text = string.Empty;
            ComboBoxDay.ItemsSource = null;
            ComboBoxTime.ItemsSource = null;
            listViewNearestTime.SelectedItem = null;
            CheckBoxBookOrdinaryDateTime.IsChecked = false;
            CheckBoxBookPreferredDate1.IsChecked = false;
            CheckBoxBookPreferredDate2.IsChecked = false;
            CheckBoxBookPreferredDate2.IsEnabled = false;
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            Mouse.OverrideCursor = Cursors.Wait;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            if(model != null)
            {
                Mouse.OverrideCursor = Cursors.Wait;

                model.CancelCommand.Execute(model);

                ClearControls();

                SaveButton.IsEnabled = false;
                CancelButton.IsEnabled = false;

                // Toggla knapparna
                CheckBoxBookOrdinaryDateTime.IsEnabled = true;
                CheckBoxBookPreferredDate1.IsEnabled = true;
                CheckBoxBookPreferredDate2.IsEnabled = false;

                // Update presentationmodel
                Model = bookingService.GetBooking(model.TicketId.Value);                
            }
        }

        private void CheckBoxBookOrdinaryDateTime_Unchecked(object sender, RoutedEventArgs e)
        {
            TextBoxMonth.Text = string.Empty;
            ComboBoxDay.ItemsSource = null;
            ComboBoxTime.ItemsSource = null;
            listViewNearestTime.SelectedItem = null;
            model.BookedDate = null;
        }

        private void CheckBoxBookPreferredDate1_Unchecked(object sender, RoutedEventArgs e)
        {
            model.PreferredDate1 = null;
            //Om datum 1 inte är valt så kan man inte välja datum 2
            model.PreferredDate2 = null;
            CheckBoxBookPreferredDate2.IsChecked = false;
            CheckBoxBookPreferredDate2.IsEnabled = false;
        }

        private void CheckBoxBookPreferredDate2_Unchecked(object sender, RoutedEventArgs e)
        {
            model.PreferredDate2 = null;
        }

        private void ComboBoxTime_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (IsLoaded && e.AddedItems != null && e.AddedItems.Count > 0)
            {
                //Om checkboxen redan är ikryssad så måste vi binda datat till modellen
                if(CheckBoxBookOrdinaryDateTime.IsChecked.Value)
                {
                    BindControlsToBookingDate();
                }
            }
        }
    }
}